import dingtalkcard_1_0, {
  CreateAndDeliverHeaders,
  CreateAndDeliverRequest,
  CreateAndDeliverRequestCardData,
  CreateAndDeliverRequestImGroupOpenDeliverModel,
  CreateAndDeliverRequestImGroupOpenSpaceModel,
  CreateAndDeliverRequestImRobotOpenDeliverModel,
  CreateAndDeliverRequestImRobotOpenSpaceModel,
  UpdateCardHeaders,
  UpdateCardRequest,
  UpdateCardRequestCardData,
  UpdateCardRequestCardUpdateOptions,
} from '@alicloud/dingtalk/dist/card_1_0/client';
import Util, * as $Util from '@alicloud/tea-util';

import { DingClientService } from './client.serivce';
import { convertJSONValuesToString, genCardId } from './utils';

interface CreateAndDeliverCardOptions {
  /** dingID */
  senderStaffId: string;
  /**
   * 卡片模板 id，在卡片后台获取
   * @link https://open-dev.dingtalk.com/fe/card
   */
  cardTemplateId: CreateAndDeliverRequest['cardTemplateId'];
  /** 卡片参数 */
  cardData: Record<string, any>;
  /** 卡片回调的类型 */
  callbackType?: 'HTTP' | 'STREAM';

  conversationType: '1' | '2';

  conversationId?: string;
  imGroupOpenSpaceModel?: CreateAndDeliverRequest['imGroupOpenSpaceModel'];
  imGroupOpenDeliverModel?: CreateAndDeliverRequest['imGroupOpenDeliverModel'];
  imRobotOpenSpaceModel?: CreateAndDeliverRequest['imRobotOpenSpaceModel'];
  imRobotOpenDeliverModel?:
    | CreateAndDeliverRequest['imRobotOpenDeliverModel']
    | Record<string, any>;
}

interface CreateAndDeliverCardHeader {
  accessToken: string;
}

interface PutCardDataCardOptions {
  outTrackId: string;
  cardData: CreateAndDeliverCardOptions['cardData'];
  userIdType?: 1 | 2;
  cardUpdateOptions?: UpdateCardRequestCardUpdateOptions;
}
interface PutCardDataCardHeader {
  accessToken: string;
}

interface OvertimeApplyOptions {
  senderStaffId: string;
  robotCode: string;
  cardData: CreateAndDeliverCardOptions['cardData'];
}

interface OvertimeApplyUpdateOptions extends PutCardDataCardOptions {
  cardData: {
    /** 状态 */
    status: string;
    /** 开始时间 */
    startDate: string;
    /** 结束时间 */
    endDate: string;
    /** 理由 */
    description: string;
    /** 天数 */
    day: string;
  };
}

interface OvertimeReviewOptions {
  /** 钉钉 id,目前固定人员 */
  senderStaffId?: string;
  /** 机器人,目前固定机器人 */
  robotCode?: string;
  cardData: {
    /** 申请记录 id */
    id: string;
    /** 申请人 */
    userName: string;
    /** 总计加班时间 */
    totalTimeText: string;
    /** 剩余加班时间 */
    remainTimeText: string;
    /** 已使用加班时间 */
    usedTimeText: string;
    /** 钉钉上的开始加班时间 */
    startDate: string;
    /** 钉钉上的结束加班时间 */
    endDate: string;
    /** 加班理由 */
    description: string;
    /** 加班时间 */
    day: string;
  };
}
interface OvertimeReviewUpdateOptions extends PutCardDataCardOptions {
  cardData: {
    /** 申请单 id */
    id: string;
    /** 开始时间 */
    startDate: string;
    /** 结束时间 */
    endDate: string;
    /** 理由 */
    description: string;
    /** 申请人 */
    userName: string;
    /** 申请天数 */
    day: string;
    /** 状态: 2 通过 3拒绝 */
    status: string;
    /** 总计加班时间 */
    totalTimeText: string;
    /** 剩余加班时间 */
    remainTimeText: string;
    /** 已使用加班时间 */
    usedTimeText: string;
  };
}

class CardService extends DingClientService {
  constructor() {
    super();
  }

  protected readonly client = new dingtalkcard_1_0(this.createClient());

  protected async createAndDeliver(
    options: CreateAndDeliverCardOptions,
    headers: CreateAndDeliverCardHeader,
  ) {
    const cardData = new CreateAndDeliverRequestCardData({
      cardParamMap: JSON.stringify(convertJSONValuesToString(options.cardData)),
    });

    const outTrackId = genCardId(
      options.cardTemplateId!,
      options.senderStaffId,
    );

    console.log("🚀 ~ CardService ~ outTrackId:", outTrackId)
    const createAndDeliverRequest = new CreateAndDeliverRequest({
      outTrackId,
      callbackType: options.callbackType || 'STREAM',
      userId: options.senderStaffId,
      cardTemplateId: options.cardTemplateId,
      cardData: cardData,
      userIdType: 1,
    });

    if (options.conversationType === '2') {
      createAndDeliverRequest.openSpaceId = `dtv1.card//IM_GROUP.${options.conversationId}`;
      createAndDeliverRequest.imGroupOpenDeliverModel =
        new CreateAndDeliverRequestImGroupOpenDeliverModel(
          options.imGroupOpenDeliverModel,
        );
      createAndDeliverRequest.imGroupOpenSpaceModel =
        new CreateAndDeliverRequestImGroupOpenSpaceModel({
          supportForward: false,
          ...options.imGroupOpenSpaceModel,
        });
    } else if (options.conversationType === '1') {
      createAndDeliverRequest.openSpaceId = `dtv1.card//IM_ROBOT.${options.senderStaffId}`;
      createAndDeliverRequest.imRobotOpenDeliverModel =
        new CreateAndDeliverRequestImRobotOpenDeliverModel({
          spaceType: 'IM_ROBOT',
          ...options.imRobotOpenDeliverModel,
        });

      createAndDeliverRequest.imRobotOpenSpaceModel =
        new CreateAndDeliverRequestImRobotOpenSpaceModel({
          supportForward: false,
          ...options.imRobotOpenSpaceModel,
        });
    }

    try {
      const createAndDeliverHeaders = new CreateAndDeliverHeaders({
        xAcsDingtalkAccessToken: headers.accessToken,
      });

      const res = await this.client.createAndDeliverWithOptions(
        createAndDeliverRequest,
        createAndDeliverHeaders,
        new $Util.RuntimeOptions({}),
      );

      if (res.statusCode === 200) {
        return res.body?.result?.outTrackId;
      }
      throw new Error('发送卡片失败: ' + JSON.stringify(res.body));
    } catch (err) {
      if (!Util.empty(err.code) && !Util.empty(err.message)) {
        throw new Error(err.message);
      } else {
        throw new Error('发送卡片失败: ' + JSON.stringify(err));
      }
    }
  }

  protected async putCardData(
    options: PutCardDataCardOptions,
    headers: PutCardDataCardHeader,
  ) {
    const updateCardHeaders = new UpdateCardHeaders({
      xAcsDingtalkAccessToken: headers.accessToken,
    });

    const cardUpdateOptions = new UpdateCardRequestCardUpdateOptions({
      updateCardDataByKey: true,
      updatePrivateDataByKey: false,
      ...options.cardUpdateOptions,
    });

    const cardData = new UpdateCardRequestCardData({
      cardParamMap: JSON.stringify(convertJSONValuesToString(options.cardData)),
    });
    const updateCardRequest = new UpdateCardRequest({
      outTrackId: options.outTrackId,
      cardData: cardData,
      cardUpdateOptions: cardUpdateOptions,
      userIdType: options.userIdType || 1,
    });
    try {
      const res = await this.client.updateCardWithOptions(
        updateCardRequest,
        updateCardHeaders,
        new $Util.RuntimeOptions({}),
      );
      if (res.statusCode !== 200) {
        throw new Error('更新卡片失败: ' + JSON.stringify(res.body));
      }
    } catch (err) {
      if (!Util.empty(err.code) && !Util.empty(err.message)) {
        throw new Error(err.message);
      } else {
        throw new Error('更新卡片失败: ' + JSON.stringify(err));
      }
    }
  }
}

export class DingCardService extends CardService {
  constructor() {
    super();
  }

  /** 加班申请卡片 */
  overtimeApply(options: OvertimeApplyOptions, accessToken: string) {
    const { senderStaffId, robotCode, cardData } = options;

    const cardTemplateId = 'd3adcc33-2b1c-4aba-ad3b-42ea16cbc65d.schema'; // 该模板只用于测试使用，如需投入线上使用，请导入卡片模板 json 到自己的应用下

    return this.createAndDeliver(
      {
        cardTemplateId,
        senderStaffId,
        cardData,
        conversationType: '1',
        imRobotOpenDeliverModel: {
          robotCode: robotCode,
        },
      },
      { accessToken },
    );
  }

  /** 更新申请加班状态 */
  overtimeApplyUpdate(
    options: OvertimeApplyUpdateOptions,
    accessToken: string,
  ) {
    return this.putCardData(
      {
        ...options,
        outTrackId: options.outTrackId,
        cardData: options.cardData,
      },
      { accessToken },
    );
  }

  /** 加班审核卡片 */
  overtimeApplyReview(options: OvertimeReviewOptions, accessToken: string) {
    const { cardData } = options;

    const senderStaffId = '104619303835158233'; // 固定审核员
    const cardTemplateId = 'f48dff46-c37d-40dd-9e70-98c88321f366.schema'; // 该模板只用于测试使用，如需投入线上使用，请导入卡片模板 json 到自己的应用下
    const robotCode = 'dingsqeymayoona1jalx';

    return this.createAndDeliver(
      {
        cardTemplateId,
        senderStaffId,
        cardData,
        conversationType: '1',
        imRobotOpenDeliverModel: {
          robotCode: robotCode,
        },
      },
      { accessToken },
    );
  }

  overtimeApplyReviewUpdate(
    options: OvertimeReviewUpdateOptions,
    accessToken: string,
  ) {
    return this.putCardData(options, { accessToken });
  }
}
